﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

using SpiritAlight.Input;
using SpiritAlight.GeneralClac;
using SpiritAlight;
using SpiritAlight.Stage;
using SpiritAlight.Character.Unit;

namespace SpiritAlight.Character
{
    /// <summary>
    /// キャラクターの向きを表します。
    /// </summary>
    public enum Direction
    {
        Up = 0,
        Down = 1,
        Left = 2,
        Right = 3,
    }

    /// <summary>
    /// キャラクターの状態を表します。
    /// </summary>
    public enum CharacterState
    {
        Wait = 0,
        Damage = 1,
        Attack = 2,
    }



    
    /// <summary>
    /// キャラクターを作る際に実装するインターフェース。
    /// </summary>
    public class AUnit
    {
        int nowAttackInterval = 0;
        int nowDamageInterval = 0;

        static int DamageInterval = 15;


        protected virtual UnitStatus Status
        {
            get;
            set;
        }

        public static Func<Vector2, Vector2, bool> IsWall;

        /// <summary>
        /// 移動目標地点
        /// </summary>
        protected Vector2 TargetPoint
        {
            get { return targetPoint; }
            set { targetPoint = value; }
        }
        Vector2 targetPoint = new Vector2(0.0f);

        /// <summary>
        /// 移動ベクトル
        /// </summary>
        protected Vector2 MoveVector
        {
            get { return moveVector; }
            set { moveVector = value; }
        }
        Vector2 moveVector = Vector2.Zero;

        /// <summary>
        /// キャラクターの座標位置。
        /// </summary>
        public Vector2 Position
        {
            get { return position; }
            protected set { position = value; }
        }
        Vector2 position = new Vector2(0.0f);

        /// <summary>
        /// 現在のキャラクターの向き
        /// </summary>
        public Direction Direction
        {
            get { return direction; }
            protected set { direction = value; }
        }
        Direction direction = Direction.Down;

        /// <summary>
        /// 現在のキャラクターの状態。
        /// </summary>
        public CharacterState State
        {
            get { return state; }
            protected set { state = value; }
        }
        CharacterState state = CharacterState.Wait;

        /// <summary>
        /// 移動中かどうかを調べるフラグ
        /// </summary>
        public bool IsMoving
        {
            get { return isMoving; }
            protected set { isMoving = value; }
        }
        bool isMoving = false;


        /// <summary>
        /// ロード完了フラグ
        /// </summary>
        virtual public bool IsLoaded
        {
            get;
            protected set;
        }
        /// <summary>
        /// 戦闘ターゲット
        /// </summary>
        public AUnit Target
        {
            get { return targetUnit; }
            set { targetUnit = value; }
        }
        AUnit targetUnit;


        /// <summary>
        /// キャラクターの初期化
        /// </summary>
        virtual public void Initialize()
        {

        }

        /// <summary>
        /// リソース読み込み。
        /// </summary>
        /// <param name="Content">コンテンツマネージャ</param>
        virtual public void LoadContent()
        {
            //読み込みを完了する
            IsLoaded = true;
        }

        //protected UnitStatus InputUnitStatus(string fileName) 
        //{
        //    //XmlSerializerオブジェクトを作成
        //    System.Xml.Serialization.XmlSerializer serializer =
        //        new System.Xml.Serialization.XmlSerializer(typeof(UnitStatus));
        //    //読み込むファイルを開く
        //    FileStream fs = new FileStream(
        //        fileName, FileMode.Open);
        //    //XMLファイルから読み込み、逆シリアル化する
        //    UnitStatus obj = (UnitStatus)serializer.Deserialize(fs);
        //    //ファイルを閉じる
        //    fs.Close();

        //    return obj;
        //}

        /// <summary>
        /// プレイヤーの更新処理。
        /// </summary>
        /// <param name="inputState">現在の入力デバイスの状態。</param>
        virtual public void Update()
        {
            if (state == CharacterState.Wait)
            {
                if (isMoving)
                    Move();
                ChangeDirection();
            }

            //if (Status.AttackInterval > 0)
            //    Status.AttackInterval--;
            //else if (state == CharacterState.Attack)
            //    state = CharacterState.Wait;


            //if (damageInterval > 0)
            //    damageInterval--;
            //else if (state == CharacterState.Damage)
            //    state = CharacterState.Wait;




        }

        /// <summary>
        /// キャラクターの描画処理。
        /// </summary>
        /// <param name="spriteBatch">描画するSpriteBatch</param>
        /// <param name="sceneColor">シーンの色。</param>
        virtual public void Draw()
        {

        }


        /// <summary>
        /// 移動を開始する。
        /// </summary>
        /// <param name="targetPoint">目標地点。</param>
        public void MoveStart(Vector2 targetPoint)
        {
            isMoving = true;
            this.targetPoint = targetPoint;
            CalcVector();
        }

        /// <summary>
        /// 移動フラグが経っている際にプレイヤーを移動させる。
        /// </summary>
        public void Move()
        {
            CalcVector();
            if (isMoving)
            {
                position.X += moveVector.X;
                if (IsWall(position, Status.Size))
                    position.X -= moveVector.X;

                position.Y += moveVector.Y;
                if (IsWall(position, Status.Size))
                    position.Y -= moveVector.Y;
            }
            if (Calc.IsApproximation(position + Status.Center, targetPoint, new Vector2(10.0f, 10.0f)))
                isMoving = false;
            CalcVector();
        }

        /// <summary>
        /// キャラクターの地点から目標地点へのベクトルを計算する。
        /// </summary>
        private void CalcVector()
        {
            moveVector = Calc.VectorFromAngle(
                Calc.Angle(position + Status.Center, targetPoint)
                );
        }

        /// <summary>
        /// キャラクターの方向を移動ベクトルに応じて変更する。
        /// </summary>
        protected void ChangeDirection()
        {
            if (Math.Abs(moveVector.X) >= Math.Abs(moveVector.Y))
            {
                if (moveVector.X < 0.0f)
                    direction = Direction.Left;
                else
                    direction = Direction.Right;
            }
            else
            {
                if (moveVector.Y < 0.0f)
                    direction = Direction.Up;
                else
                    direction = Direction.Down;
            }
        }


        /// <summary>
        /// ユニットをサーチする。
        /// 範囲内にいれば攻撃を行う、
        /// </summary>
        /// <param name="unitList">サーチする対象のリスト</param>
        virtual public void SearchOperation<T>(List<T> unitList) where T : AUnit
        {
            foreach (var unit in unitList)
            {
                if (Vector2.Distance(unit.Status.Center, this.Status.Center) < Status.RangeSearchOperation)
                {
                    if (targetUnit == null)
                    {
                        targetUnit = unit;
                        MoveStart(unit.position);
                    }
                    break;
                }
                else
                {
                    if (targetUnit != null)
                    {
                        targetUnit = null;
                    }
                }
            }
        }

        /// <summary>
        /// 攻撃をする。
        /// </summary>
        /// <param name="unit">攻撃対象</param>
        public void Attack()
        {
            //範囲内ならば攻撃、範囲外ならば敵に向かって移動。
            if (Vector2.Distance(Status.Center, targetUnit.Status.Center) <= Status.RangeAttackOperation)
            {
                if (nowAttackInterval == 0 && state != CharacterState.Damage)
                {
                    state = CharacterState.Attack;
                    nowAttackInterval = Status.AttackInterval;
                    targetUnit.Damage(this);
                    targetUnit.targetUnit = this;
                }
            }
            else
            {
                //targetPoint = targetUnit.Status.Center;
                CalcVector();
            }
        }

        public void Damage(AUnit Attacker)
        {
            state = CharacterState.Damage;
            //nowDamageInterval = Status.DamageInterval;
            Status.HitPoint -= Status.Power;
            if (!isMoving)
                targetUnit = Attacker;
        }

        public void BattleAnimation()
        {
            if (state == CharacterState.Attack)
            {
                if (nowAttackInterval < Status.AttackInterval / 2)
                {
                    state = CharacterState.Wait;
                }
            }
            if (state == CharacterState.Damage)
            {
                if (nowDamageInterval < DamageInterval)
                {
                    state = CharacterState.Wait;
                }
            }
        }
    }
}
